package org.chen.service.impl;

import com.alibaba.nacos.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.chen.common.constant.ArticleStatusEnum;
import org.chen.common.constant.VideoStatusEnum;
import org.chen.common.exception.ServiceException;
import org.chen.common.utils.SnowflakeIdGenerator;
import org.chen.domain.dto.ArticleImportDTO;
import org.chen.domain.dto.ArticleQueryDTO;
import org.chen.domain.dto.ArticleUpdateDTO;
import org.chen.domain.entity.VideoArticle;
import org.chen.domain.response.PageResult;
import org.chen.domain.vo.*;
import org.chen.client.CategoryFeignClient;
import org.chen.mapper.ArticleMapper;
import org.chen.service.ArticleService;
import org.chen.service.TranslationService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, VideoArticle> implements ArticleService {
    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private CategoryFeignClient categoryFeignClient;

//    @Autowired
    private TranslationService translationService;

    private final ExecutorService importExecutor =
            new ThreadPoolExecutor(
                    4, 8, 60L, TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(1000),
                    new ThreadFactoryBuilder().setNameFormat("article-import-%d").build()
            );

    private static final int BATCH_SIZE = 500; // 更大的批量处理大小
    private static final int PARALLEL_THRESHOLD = 1000; // 启用并行处理的阈值

    @Override
    public ImportResultVO importArticles(List<ArticleImportDTO.Article> articles, String categoryId) {
        try {
            // 1. 验证分类ID
            CategoryVO category = categoryFeignClient.getCategory(categoryId).getData();
            if (category == null) {
                throw new ServiceException("分类不存在");
            }

            // 2. 批量检查标题（使用Set提高查重效率）
            Set<String> titleSet = articles.stream()
                    .map(ArticleImportDTO.Article::getTitle)
                    .collect(Collectors.toSet());

            // 使用一次查询获取所有存在的标题
            List<String> existingTitles = articleMapper.findExistingTitles(new ArrayList<>(titleSet));
            if (!existingTitles.isEmpty()) {
                throw new ServiceException("以下文章标题已存在：" + String.join(", ", existingTitles));
            }

            // 3. 转换数据（并行处理大量数据）
            List<VideoArticle> videoArticles;
            if (articles.size() >= PARALLEL_THRESHOLD) {
                videoArticles = articles.parallelStream()
                        .map(article -> convertToVideoArticle(article, categoryId, category.getPath()))
                        .collect(Collectors.toList());
            } else {
                videoArticles = articles.stream()
                        .map(article -> convertToVideoArticle(article, categoryId, category.getPath()))
                        .collect(Collectors.toList());
            }

            // 4. 使用CompletableFuture进行异步批量插入
            List<CompletableFuture<Void>> futures = new ArrayList<>();
            List<List<VideoArticle>> batches = Lists.partition(videoArticles, BATCH_SIZE);

            for (List<VideoArticle> batch : batches) {
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        articleMapper.batchInsert(batch);
                        log.info("Successfully inserted batch of {} articles", batch.size());
                    } catch (Exception e) {
                        log.error("Failed to insert batch", e);
                        throw new CompletionException(e);
                    }
                }, importExecutor);
                futures.add(future);
            }

            // 4. 等待所有批次完成
            try {
                CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
            } catch (CompletionException e) {
                throw new ServiceException("部分数据导入失败：" + e.getMessage());
            }

            return new ImportResultVO(articles.size());
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            log.error("Import articles failed", e);
            throw new ServiceException("导入文章失败：" + e.getMessage());
        }
    }

    private VideoArticle convertToVideoArticle(ArticleImportDTO.Article article,
                                               String categoryId, String categoryPath) {
        VideoArticle videoArticle = new VideoArticle();
        videoArticle.setId(SnowflakeIdGenerator.nextId());
        videoArticle.setTitle(article.getTitle().trim());
        videoArticle.setDescription(article.getDescription());
        videoArticle.setSource("admin");
        videoArticle.setVersion(1);
        videoArticle.setArticleTimestamp(LocalDateTime.parse(article.getTimestamp()));
        videoArticle.setStatus(ArticleStatusEnum.PENDING.getCode());
        videoArticle.setCategoryId(categoryId);        // 设置分类ID
        videoArticle.setCategoryPath(categoryPath);    // 设置分类路径
        return videoArticle;
    }

    @Override
    public PageResult<ArticleVO> getArticleList(ArticleQueryDTO query) {
        Page<VideoArticle> page = new Page<>(query.getPageNum(), query.getPageSize());

        LambdaQueryWrapper<VideoArticle> wrapper = new LambdaQueryWrapper<VideoArticle>()
                .eq(VideoArticle::getSource, query.getSource())
                .like(StringUtils.isNotBlank(query.getTitle()), VideoArticle::getTitle, query.getTitle())
                .eq(query.getStatus() != null, VideoArticle::getStatus, query.getStatus())
                .eq(StringUtils.isNotBlank(query.getCategoryId()), VideoArticle::getCategoryId, query.getCategoryId())
                .orderByDesc(VideoArticle::getCreateTime);

        Page<VideoArticle> resultPage = articleMapper.selectPage(page, wrapper);

        // 获取所有分类ID
        Set<String> categoryIds = resultPage.getRecords().stream()
                .map(VideoArticle::getCategoryId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        // 批量获取分类信息
        Map<String, CategoryVO> categoryMap = new HashMap<>();
        if (!categoryIds.isEmpty()) {
            try {
                List<CategoryVO> categories = categoryFeignClient.getCategoriesByIds(new ArrayList<>(categoryIds)).getData();
                categoryMap = categories.stream()
                        .collect(Collectors.toMap(CategoryVO::getId, category -> category));
            } catch (Exception e) {
                log.error("Failed to get categories", e);
            }
        }

        Map<String, CategoryVO> finalCategoryMap = categoryMap;
        List<ArticleVO> voList = resultPage.getRecords().stream()
                .map(article -> convertToVO(article, finalCategoryMap.get(article.getCategoryId())))
                .collect(Collectors.toList());

        return new PageResult<>(voList,
                resultPage.getTotal(),
                resultPage.getSize(),
                resultPage.getCurrent());
    }

    @Override
    public ArticleVO getArticleDetail(String id) {
        ArticleVO article = articleMapper.selectArticleWithVideo(id);
        if (article == null) {
            throw new ServiceException("文章不存在");
        }
        // 转换状态描述
        article.setStatus(ArticleStatusEnum.getDesc(Integer.parseInt(article.getStatus())));
        if (article.getVideoStatus() != null) {
            article.setVideoStatus(VideoStatusEnum.getDesc(Integer.parseInt(article.getVideoStatus())));
        }
        return article;
    }

    @Override
    public void updateArticleStatus(String id, Integer status) {
        int rows = articleMapper.updateStatus(id, status);
        if (rows == 0) {
            throw new ServiceException("更新文章状态失败");
        }
    }

    @Override
    public void deleteArticle(String id) {
        // 检查文章状态，只有未处理的文章才能删除
        VideoArticle article = articleMapper.selectById(id);
        if (article == null) {
            throw new ServiceException("文章不存在");
        }

        articleMapper.deleteById(id);
    }

    private ArticleVO convertToVO(VideoArticle article, CategoryVO category) {
        ArticleVO vo = new ArticleVO();
        BeanUtils.copyProperties(article, vo);
        vo.setStatus(ArticleStatusEnum.getDesc(article.getStatus()));
        vo.setArticleTimestamp(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
                .format(article.getArticleTimestamp()));
        vo.setImportTimestamp(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
                .format(article.getImportTimestamp()));

        // 设置分类信息
        if (category != null) {
            vo.setCategoryName(category.getName());
        }

        return vo;
    }

    @Override
    public void batchDelete(List<String> ids) {
        // 批量删除
        articleMapper.deleteByIds(ids);
    }

    @Override
    public void updateArticle(ArticleUpdateDTO updateDTO) {
        // 检查文章是否存在
        VideoArticle article = articleMapper.selectById(updateDTO.getId());
        if (article == null) {
            throw new ServiceException("文章不存在");
        }

        // 如果提供了标题和描述，更新原文
        if (StringUtils.isNotBlank(updateDTO.getTitle()) || updateDTO.getDescription() != null) {
            VideoArticle updateArticle = new VideoArticle();
            updateArticle.setId(updateDTO.getId());

            // 只有在提供了新值的情况下才更新
            if (StringUtils.isNotBlank(updateDTO.getTitle())) {
                updateArticle.setTitle(updateDTO.getTitle());
            }

            if (updateDTO.getDescription() != null) {
                updateArticle.setDescription(updateDTO.getDescription());
            }

            // 更新文章信息
            int rows = articleMapper.updateById(updateArticle);
            if (rows == 0) {
                throw new ServiceException("更新文章失败");
            }
        }

        // 如果设置了目标语言，保存翻译版本
//        if (StringUtils.isNotBlank(updateDTO.getTargetLanguage())) {
//            translationService.saveOrUpdateTranslation(
//                    updateDTO.getId(),
//                    updateDTO.getTargetLanguage(),
//                    updateDTO.getTitle(),
//                    updateDTO.getDescription()
//            );
//        }
    }

    @Override
    public BatchSaveResultVO batchUpdateArticles(List<ArticleUpdateDTO> articles) {
        if (CollectionUtils.isEmpty(articles)) {
            throw new ServiceException("文章列表不能为空");
        }

        // 结果统计
        BatchSaveResultVO result = new BatchSaveResultVO();
        result.setTotalCount(articles.size());
        result.setSuccessCount(0);
        result.setFailCount(0);
        result.setResults(new ArrayList<>());

        for (ArticleUpdateDTO updateDTO : articles) {
            BatchSaveResultVO.SaveResult saveResult = new BatchSaveResultVO.SaveResult();
            saveResult.setId(updateDTO.getId());

            try {
                // 检查文章是否存在
                VideoArticle article = articleMapper.selectById(updateDTO.getId());
                if (article == null) {
                    saveResult.setSuccess(false);
                    saveResult.setMessage("文章不存在");
                    result.setFailCount(result.getFailCount() + 1);
                } else {
                    // 更新文章
                    VideoArticle updateArticle = new VideoArticle();
                    updateArticle.setId(updateDTO.getId());

                    if (StringUtils.isNotBlank(updateDTO.getTitle())) {
                        updateArticle.setTitle(updateDTO.getTitle());
                    }

                    if (updateDTO.getDescription() != null) {
                        updateArticle.setDescription(updateDTO.getDescription());
                    }

                    int rows = articleMapper.updateById(updateArticle);
                    if (rows > 0) {
                        saveResult.setSuccess(true);
                        result.setSuccessCount(result.getSuccessCount() + 1);
                    } else {
                        saveResult.setSuccess(false);
                        saveResult.setMessage("更新失败");
                        result.setFailCount(result.getFailCount() + 1);
                    }
                }
            } catch (Exception e) {
                log.error("Failed to update article {}", updateDTO.getId(), e);
                saveResult.setSuccess(false);
                saveResult.setMessage(e.getMessage());
                result.setFailCount(result.getFailCount() + 1);
            }

            result.getResults().add(saveResult);
        }

        return result;
    }
}
